package com.zijidelu.luframework.utils.persistence.mybatisplus;

import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.zijidelu.luframework.utils.CastUtil;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * Mybatis-Plus QueryWrapper工具类。
 *
 * @author ZIJIDELU
 * @date: 2023/10/18 15:03
 */
public class MybatisPlusWrapperUtil {
    /**
     * 计算数据范围。
     *
     * @param queryWrapper 查询条件构造器
     * @param column       字段
     * @param start        开始
     * @param end          结束
     * @param <T>          实体泛型
     * @param <Param>      抽象条件构造器
     * @return 查询条件构造器
     */
    public static <T, Param extends AbstractWrapper<T, String, QueryWrapper<T>>> Param
    rangeQuery(final Param queryWrapper, final String column, final Object start, final Object end) {
        queryWrapper.between(Objects.nonNull(start) && Objects.nonNull(end), column, start, end)
                .ge(Objects.nonNull(start) && Objects.isNull(end), column, start)
                .le(Objects.isNull(start) && Objects.nonNull(end), column, end);
        return queryWrapper;
    }

    /**
     * 计算数据范围。
     *
     * @param lambdaQueryWrapper 函数式条件构造器
     * @param column             字段
     * @param start              开始
     * @param end                结束
     * @param <T>                实体类型
     * @param <Wrapper>          条件构造器
     * @return 函数式条件构造器
     */
    public static <T, Wrapper extends LambdaQueryWrapper<T>> Wrapper rangeLambdaQuery(final Wrapper lambdaQueryWrapper,
                                                                                      final SFunction<T, ?> column,
                                                                                      final Object start,
                                                                                      final Object end) {
        lambdaQueryWrapper.between(Objects.nonNull(start) && Objects.nonNull(end), column, start, end)
                .ge(Objects.nonNull(start) && Objects.isNull(end), column, start)
                .le(Objects.isNull(start) && Objects.nonNull(end), column, end);
        return lambdaQueryWrapper;
    }

    /**
     * lambdaQueryWrapper转QueryWrapper。
     *
     * @param lambdaQueryWrapper 函数式条件查询器
     * @param <T>                实体类泛型
     * @return QueryWrapper
     */
    public static <T> QueryWrapper<T> lambdaToQueryWrapper(final LambdaQueryWrapper<T> lambdaQueryWrapper) {
        final QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        final Map<String, Object> fieldMap = new HashMap<>(MybatisPlusConstant.BUILD_QUERY_WRAPPER_REQUIRED_FIELD_NAMES.size());
        try {
            // 获取LambdaQueryWrapper中的数据
            for (Field declaredField : MybatisPlusConstant.LAMBDA_QUERY_WRAPPER_FIELDS) {
                declaredField.setAccessible(true);
                if (MybatisPlusConstant.BUILD_QUERY_WRAPPER_REQUIRED_FIELD_NAMES.contains(declaredField.getName())) {
                    fieldMap.put(declaredField.getName(), declaredField.get(lambdaQueryWrapper));
                }
            }
            // 设置QueryWrapper中的数据
            for (String fieldName : MybatisPlusConstant.BUILD_QUERY_WRAPPER_REQUIRED_FIELD_NAMES) {
                final Field declaredField = MybatisPlusConstant.QUERY_WRAPPER_FIELD_MAP.get(fieldName);
                declaredField.setAccessible(true);
                declaredField.set(queryWrapper, fieldMap.get(fieldName));
            }

        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        return queryWrapper;
    }

    /**
     * QueryWrapper转LambdaQueryWrapper。
     *
     * @param queryWrapper 查询包装器
     * @param <T>          实体类型
     * @return lambdaQueryWrapper
     */
    public static <T> LambdaQueryWrapper<T> queryToLambdaWrapper(final QueryWrapper<T> queryWrapper) {
        return queryWrapper.lambda();
    }

    /**
     * QueryChainWrapper设置QueryWrapper。
     *
     * @param queryChainWrapper 链包装器
     * @param queryWrapper      查询包装器
     * @param <T>               实体类型
     * @return 链查询器器
     */
    public static <T> QueryChainWrapper<T> setQueryWrapper(final QueryChainWrapper<T> queryChainWrapper,
                                                           final QueryWrapper<T> queryWrapper) {
        final Field wrapperChildrenField = MybatisPlusConstant.QUERY_CHAIN_WRAPPER_FIELD_MAP.get(MybatisPlusConstant.WRAPPER_CHILDREN_FIELD_NAME);
        wrapperChildrenField.setAccessible(true);
        try {
            wrapperChildrenField.set(queryChainWrapper, queryWrapper);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return queryChainWrapper;
    }

    /**
     * LambdaQueryChainWrapper设置QueryWrapper。
     *
     * @param lambdaQueryChainWrapper 链包装器
     * @param queryWrapper            查询包装器
     * @param <T>                     实体类型
     * @return 链查询器器
     */
    public static <T> LambdaQueryChainWrapper<T> setQueryWrapper(final LambdaQueryChainWrapper<T> lambdaQueryChainWrapper,
                                                                 final QueryWrapper<T> queryWrapper) {
        setLambdaQueryWrapper(lambdaQueryChainWrapper, queryWrapper.lambda());
        return lambdaQueryChainWrapper;
    }

    /**
     * QueryChainWrapper设置QueryWrapper。
     *
     * @param chainWrapper 链包装器
     * @param <T>          实体类型
     * @return 查询器器
     */
    public static <T> QueryWrapper<T> getQueryWrapper(final QueryChainWrapper<T> chainWrapper) {
        final Field wrapperChildrenField = MybatisPlusConstant.QUERY_CHAIN_WRAPPER_FIELD_MAP.get(MybatisPlusConstant.WRAPPER_CHILDREN_FIELD_NAME);
        wrapperChildrenField.setAccessible(true);
        try {
            return CastUtil.cast(wrapperChildrenField.get(chainWrapper));
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * LambdaQueryChainWrapper设置QueryWrapper。
     *
     * @param lambdaQueryChainWrapper 链包装器
     * @param <T>                     实体类型
     * @return 查询器器
     */
    public static <T> QueryWrapper<T> getQueryWrapper(final LambdaQueryChainWrapper<T> lambdaQueryChainWrapper) {
        final LambdaQueryWrapper<T> lambdaQueryWrapper = getLambdaQueryWrapper(lambdaQueryChainWrapper);
        return lambdaToQueryWrapper(lambdaQueryWrapper);
    }

    /**
     * LambdaQueryChainWrapper设置LambdaQueryWrapper。
     *
     * @param lambdaQueryChainWrapper 链包装器
     * @param lambdaQueryWrapper      查询包装器
     * @param <T>                     实体类型
     * @return 函数式链查询器器
     */
    public static <T> LambdaQueryChainWrapper<T> setLambdaQueryWrapper(final LambdaQueryChainWrapper<T> lambdaQueryChainWrapper,
                                                                       final LambdaQueryWrapper<T> lambdaQueryWrapper) {
        final Field wrapperChildrenField = MybatisPlusConstant.LAMBDA_QUERY_CHAIN_WRAPPER_FIELD_MAP.get(MybatisPlusConstant.WRAPPER_CHILDREN_FIELD_NAME);
        wrapperChildrenField.setAccessible(true);
        try {
            wrapperChildrenField.set(lambdaQueryChainWrapper, lambdaQueryWrapper);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return lambdaQueryChainWrapper;
    }

    /**
     * QueryChainWrapper设置LambdaQueryWrapper。
     *
     * @param queryChainWrapper  链包装器
     * @param lambdaQueryWrapper 查询包装器
     * @param <T>                实体类型
     * @return 函数式链查询器器
     */
    public static <T> QueryChainWrapper<T> setLambdaQueryWrapper(final QueryChainWrapper<T> queryChainWrapper,
                                                                 final LambdaQueryWrapper<T> lambdaQueryWrapper) {
        setQueryWrapper(queryChainWrapper, lambdaToQueryWrapper(lambdaQueryWrapper));
        return queryChainWrapper;
    }

    /**
     * 从LambdaQueryChainWrapper获取LambdaQueryWrapper。
     *
     * @param lambdaQueryChainWrapper 链包装器
     * @param <T>                     实体类型
     * @return 链查询器器
     */
    public static <T> LambdaQueryWrapper<T> getLambdaQueryWrapper(final LambdaQueryChainWrapper<T> lambdaQueryChainWrapper) {
        final Field wrapperChildrenField = MybatisPlusConstant.LAMBDA_QUERY_CHAIN_WRAPPER_FIELD_MAP.get(MybatisPlusConstant.WRAPPER_CHILDREN_FIELD_NAME);
        wrapperChildrenField.setAccessible(true);
        try {
            return CastUtil.cast(wrapperChildrenField.get(lambdaQueryChainWrapper));
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 从QueryChainWrapper获取LambdaQueryWrapper。
     *
     * @param queryChainWrapper 链包装器
     * @param <T>               实体类型
     * @return 链查询器器
     */
    public static <T> LambdaQueryWrapper<T> getLambdaQueryWrapper(final QueryChainWrapper<T> queryChainWrapper) {
        return getQueryWrapper(queryChainWrapper).lambda();
    }

}
